using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Def.Log;
using MPlayer.Common;

namespace FrontDisplay.Music
{
    public class MusicClientManager : BaseMusicPlayerManager
    {
        private readonly List<IMusicPlayer> _players = new List<IMusicPlayer>();
        private const string PluginsDir = "Plugins";

        public MusicClientManager()
        {
            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainAssemblyResolve;
            try
            {
                //TODO: plugins initialization
                string pluginsDir = Utility.MapPath(PluginsDir);
                if (Directory.Exists(pluginsDir))
                {
                    string[] libs = Directory.GetFiles(pluginsDir, "*.dll");
                    foreach (string fileName in libs)
                    {
                        Logger.Debug(string.Format("Searching for plugins in '{0}'.", fileName));
                        try
                        {
                            Assembly assembly = Assembly.LoadFile(fileName);
                            IEnumerable<Type> pluginsTypes =
                                assembly.GetTypes().Where(
                                    t => t.IsClass && !t.IsAbstract && typeof (IMusicPlayer).IsAssignableFrom(t));

                            foreach (Type pluginType in pluginsTypes)
                            {
                                Logger.Debug(string.Format("Initializing plugin '{0}'.", pluginType));
                                IMusicPlayer player = (IMusicPlayer) Activator.CreateInstance(pluginType);
                                InitializePlayer(player);
                                _players.Add(player);
                            }
                        }
                        catch (BadImageFormatException)
                        {
                        }
                        catch (Exception ex)
                        {
                            Logger.Error(ex);
                        }
                    }
                }
            }
            finally
            {
                AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomainAssemblyResolve;
            }
        }

        private static Assembly CurrentDomainAssemblyResolve(object sender, ResolveEventArgs args)
        {
            Logger.Debug("Loading assembly '" + args.Name + "'");
            string pluginsDir = Utility.MapPath(PluginsDir);

            if (Directory.Exists(pluginsDir))
            {
                string fileName = pluginsDir + args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll";
                
                if (File.Exists(fileName))
                {
                    Assembly assembly = Assembly.LoadFile(fileName);
                    Logger.Debug("Assembly '" + args.Name + "' loaded.");
                    return assembly;
                    
                }
            }

            return null;
        }

        protected override void PlayerStateChanged(object sender, PlayerStateEventArgs e)
        {
            IMusicPlayer player = sender as IMusicPlayer;
            if (player == null) return;

            IMusicPlayer oldPlayer = _player;

            if (e.State == PlayerState.Playing)
            {
                _player = player;
            }

            if ((e.State == PlayerState.Stopped) || (e.State == PlayerState.Unknown))
            {
                _player = GetActivePlayer();
            }

            if (oldPlayer != _player)
            {
                OnCurrentPlayerChanged();
            }

            if (sender != _player) return;
            OnStateChanged(e.State);
        }

        private IMusicPlayer GetActivePlayer()
        {
            foreach (var item in _players)
            {
                if (item.State == PlayerState.Playing)
                {
                    return item;
                }
            }

            if (_player.State != PlayerState.Unknown)
            {
                return _player;
            }

            foreach (var item in _players)
            {
                if (item.State != PlayerState.Unknown)
                {
                    return item;
                }
            }

            return _player;
        }

        private void ConnectPlayer(IMusicPlayer player)
        {
            try
            {
                player.Connect();
                if ((_player == NullMusicPlayer.Instance) && (player.State != PlayerState.Unknown))
                {
                    _player = player;
                    OnCurrentPlayerChanged();
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
            }
        }

        public override void Connect()
        {
            foreach (var player in _players)
            {
                IMusicPlayer musicPlayerClient = player;
                ((Action) (() => ConnectPlayer(musicPlayerClient))).BeginInvoke(null, null);
            }
        }

        public override void Disconnect()
        {
            foreach (var player in _players)
            {
                player.Disconnect();
            }
        }

        public override void Dispose()
        {
            foreach (var player in _players)
            {
                player.Dispose();
            }
        }

        public int Count
        {
            get
            {
                return _players.Count;
            }
        }

        public IEnumerable<IMusicPlayer> Players
        {
            get
            {
                return _players;
            }
        }
    }
}